/**  
 * @author renbangjie renbangjie@126.com  
 * @date 2016-4-15 上午10:39:10
 * @version V1.0  
 * <b>Copyright (c)</b> 2014医信金融信息服务（上海）有限公司-版权所有<br/>
 */
package com.yjd.bi.statistic.control;

import java.util.*;

import com.alibaba.fastjson.JSON;
import com.yjd.bi.market.model.InvalidChannelDataCommentModel;
import com.yjd.bi.market.model.MarketChannelModel;
import com.yjd.bi.market.service.IInvalidChannelDataCommentService;
import com.yjd.bi.user.dto.UserStaticsInfoDto;
import com.yjd.bi.user.model.UserStatisticInfoModel;
import com.yjd.bi.user.service.*;
import com.yjd.comm.util.*;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.yjd.bi.comm.utils.BiDateUtil;
import com.yjd.bi.market.service.IMarketChannelService;
import com.yjd.bi.market.service.IMarketStatisticsService;
import com.yjd.bi.report.enums.TimeType;
import com.yjd.bi.report.model.EChartsModel;
import com.yjd.comm.annotation.DateString;
import com.yjd.comm.annotation.ServiceRemoteProxy;
import com.yjd.comm.base.control.BaseControl;
import com.yjd.comm.base.enums.DbWREnums;
import com.yjd.comm.rpm.RpmServiceKeyEnum;

/**
 * 用户数相关统计
 * 
 * @author renbangjie renbangjie@126.com
 * @date 2016-4-15 上午10:39:10
 */
@Controller
@Scope("prototype")
@RequestMapping("market")
public class MarketControl extends BaseControl {

	/**
	 * 用户信息统计页面
	 * 
	 * @return
	 * @throws Exception
	 *             String
	 */
	@RequestMapping("index")
	public String index() throws Exception {
		request.setAttribute("start", "2016-01-01");
		request.setAttribute("channel", this.marketChannelService.getModelList(FrameUtil.newHashMap(), DbWREnums.READ));
		request.setAttribute("end", BiDateUtil.initBiDate());
		return "market.index";
	}

	/**
	 * 总览
	 * 
	 * @throws Exception
	 *             void
	 */
	@RequestMapping("summary")
	public void summary(@DateString String start, @DateString String end,
			@RequestParam(required = false) Long channel)
			throws Exception {
		Map<String, Object> paramMap = ServletUtil.getParameterMap(request);
		paramMap.put("start", FrameUtil.getTime(DateUtil.parseDate(start,
				DateUtil.PATTERN_yyyyMMdd)));
		paramMap.put("end", FrameUtil.getTime(DateUtil.parseDate(end,
				DateUtil.PATTERN_yyyyMMdd))+86399);
		paramMap.put("channel_id", channel);
		Map<String, Object> resultMap = new HashMap<String, Object>();
		// 注册用户数
		resultMap.put("register_account",
				marketStatisticsService.register_account(paramMap));
		// 充值用户数
		resultMap.put("recharge_account",
				marketStatisticsService.recharge_account(paramMap));
		// 投资用户数
		resultMap.put("invest_account",
				marketStatisticsService.invest_account(paramMap));

		// 充值金额
		resultMap.put("recharge_price",
				marketStatisticsService.recharge_price(paramMap));

		// 投资金额
		resultMap.put("invest_price",
				marketStatisticsService.invest_price(paramMap));

		super.successData(resultMap);
	}

	/**
	 * 统计
	 * 
	 * @throws Exception
	 *             void
	 */
	@RequestMapping("count")
	public void investCount(@RequestParam(required = false) Integer timeType,
			@DateString String timeFrom,
			@RequestParam(required = false) String field,
			@RequestParam(required = false) Long channel) throws Exception {
		EChartsModel echartsMoel = marketStatisticsService.getDates(
				TimeType.getType(timeType), Long.valueOf(timeFrom), field,channel);
		super.successData(FrameUtil.newHashMap("option", echartsMoel));
	}

    @RequestMapping("channel/invalid/data/submit")
    public String channelInvalidDataSubmit(InvalidChannelDataCommentModel icdcm) throws Exception {
        if(     icdcm == null ||
                StringUtil.isEmpty(icdcm.getStart_date()) ||
                StringUtil.isEmpty(icdcm.getEnd_date()) ||
                StringUtil.isEmpty(icdcm.getContent())){
            FrameUtil.throwBaseException1("数据不完整");
        }
        long now = FrameUtil.getTime();
        icdcm.setCreate_time(now);
        icdcm.setUpdate_time(now);
        invalidChannelDataCommentService.insert(icdcm);

        return "redirect:/market/channel/invalid/data/list.action";
    }

    @RequestMapping("channel/invalid/data/delete")
    public String channelInvalidDataDelete(Long id) throws Exception {
        if(id != null){
            invalidChannelDataCommentService.delete(id);
        }

        return "redirect:/market/channel/invalid/data/list.action";
    }

    @RequestMapping("channel/invalid/data/list")
    public String channelInvalidDataList() throws Exception {
        // 渠道数据异常记录
        request.setAttribute("invalidData", invalidChannelDataCommentService.getModelList(FrameUtil.newHashMap("sort", " start_date desc "), DbWREnums.READ));

        return "invalid.channel.data";
    }

    /**
     * 渠道效果报表
     * @param selectedStart 选择的开始日期
     * @param selectedEnd 选择的结束日期
     * @param channel 用户渠道
     * @param transferPeriod 转化周期（指在周期天数内完成注册、开户、首冲、首投）
     * @return
     * @throws Exception
     */
	@RequestMapping("channel/statics/index")
	public String channelStaticsIdex(String selectedStart, String selectedEnd,
									 Long channel, Integer transferPeriod) throws Exception {
	    if(transferPeriod == null){
	        transferPeriod = 7;
        }
        transferPeriod = transferPeriod -1; // 1表示当天

		if(StringUtil.isEmpty(selectedStart)){
		    // 默认显示最近3个月的数据
            selectedStart = DateUtil.format(DateUtil.addMonth(new Date(), -3), DateUtil.PATTERN_yyyy_MM_dd);
		}
		if(StringUtil.isEmpty(selectedEnd)){
            selectedEnd = BiDateUtil.initBiDate();
		}

		List<MarketChannelModel> marketChannels = this.marketChannelService.getModelList(FrameUtil.newHashMap(), DbWREnums.READ);
		if(marketChannels == null || marketChannels.size() == 0){
			FrameUtil.throwBaseException1("渠道来源不正确");
		}
		MarketChannelModel currentChannel = null;
		for(MarketChannelModel mcm : marketChannels){
			if(channel == null || mcm.getId().intValue() == channel.intValue()) {
				currentChannel = mcm;
				break;
			}
		}
		if(currentChannel == null){
			FrameUtil.throwBaseException1("渠道不存在");
		}

		long startTime = DateUtil.getFristSecond(DateUtil.dateStringToTimestamp(selectedStart.replace("-", ""), DateUtil.PATTERN_yyyyMMdd));
		long endTime = DateUtil.getLastSecond(DateUtil.dateStringToTimestamp(selectedEnd.replace("-", ""), DateUtil.PATTERN_yyyyMMdd));

		List<UserStatisticInfoModel> channelUserStatics = userService.queryChannelUserStatics(FrameUtil.newHashMap(
				"channel_id", currentChannel.getId(),
				"regdate_gte", startTime,
				"regdate_lte", endTime,
				"transferPeriod", transferPeriod));

        // 验证/补充 数据
        validateAndFilterData(transferPeriod, channelUserStatics);

        // 计算趋势图数据
        calcLineChartData(startTime, endTime, transferPeriod, channelUserStatics);

        // 计算漏斗图数据
		request.setAttribute("funnelData", JSON.toJSONString(calcFunnelChartData(transferPeriod, channelUserStatics)));

        // 渠道数据异常记录
        request.setAttribute("invalidData", invalidChannelDataCommentService.getModelList(FrameUtil.newHashMap("sort", " start_date desc "), DbWREnums.READ));

        request.setAttribute("channelName", currentChannel.getChannel_name());
        request.setAttribute("start", "2014-01-01");
		request.setAttribute("end", BiDateUtil.initBiDate());
        request.setAttribute("selectedStart", selectedStart);
        request.setAttribute("selectedEnd", selectedEnd);
		request.setAttribute("channel", marketChannels);
        request.setAttribute("transferPeriod", transferPeriod + 1);
		return "channel.statics.index";
	}

    private void calcLineChartData(long startTime, long endTime, int transferPeriod, List<UserStatisticInfoModel> channelUserStatics) throws Exception {

        Map<String, UserStaticsInfoDto> dataOfDate = FrameUtil.newHashMap();

        List lineChartData = FrameUtil.newArrayList();

        // 生成日期列表
        String dateStr = null;
        List<String> dateList = FrameUtil.newArrayList();
        for(; startTime <= endTime; startTime += DateUtil.DAY_IN_SECOND){
            dateStr = DateUtil.timestampToDateString(startTime, DateUtil.PATTERN_yyyy_MM_dd);
            dateList.add(dateStr);
            dataOfDate.put(dateStr, new UserStaticsInfoDto());
        }
        lineChartData.add(dateList);

        // 统计每日数据
        for(UserStatisticInfoModel usim : channelUserStatics){

            UserStaticsInfoDto sts = null;
            dateStr = DateUtil.timestampToDateString(usim.getRegister_time(), DateUtil.PATTERN_yyyy_MM_dd);
            if(dataOfDate.containsKey(dateStr)){
                sts = dataOfDate.get(dateStr);
            } else {
                sts = new UserStaticsInfoDto();
                dataOfDate.put(dateStr, sts);
            }

            sts.setRegister_count(1+ sts.getRegister_count());

            if(usim.getOpen_account_time() != null && usim.getOpen_account_time().longValue() > 0){
                if(DateUtil.getTimeStempBetweenDay(DateUtil.getFristSecond(usim.getRegister_time()), DateUtil.getLastSecond(usim.getOpen_account_time())) > transferPeriod ){
                    continue;
                }
                sts.setOpen_account_count(1+ sts.getOpen_account_count());
            }

            if(usim.getFirst_recharge_time() != null && usim.getFirst_recharge_time().longValue() > 0){
                if(DateUtil.getTimeStempBetweenDay(DateUtil.getFristSecond(usim.getRegister_time()), DateUtil.getLastSecond(usim.getFirst_recharge_time())) > transferPeriod ){
                    continue;
                }
                sts.setFirst_recharge_count(1+ sts.getFirst_recharge_count());
            }

            if(usim.getFirst_invest_time() != null && usim.getFirst_invest_time().longValue() > 0){
                if(DateUtil.getTimeStempBetweenDay(DateUtil.getFristSecond(usim.getRegister_time()), DateUtil.getLastSecond(usim.getFirst_invest_time())) > transferPeriod ){
                    continue;
                }
                sts.setFirst_invest_count(1+ sts.getFirst_invest_count());
            }
        }

        // 生成数据列表
        double[] zcToktcg = new double[dateList.size()]; // 注册>开通存管
        double[] ktcgTosc = new double[dateList.size()]; // 开通存管>首次充值
        double[] scTost = new double[dateList.size()]; // 首次充值>首次投资
        double[] all = new double[dateList.size()]; // 总转化率

        int idx = 0;
        UserStaticsInfoDto usid = null;
        for(String existedDateStr : dataOfDate.keySet()){
            usid = dataOfDate.get(existedDateStr);
            idx = dateList.indexOf(existedDateStr);
            if(idx < 0){
                continue;
            }

            if(usid.getOpen_account_count() != 0){
                zcToktcg[idx] = Double.valueOf( NumberUtil.formatNumber( ((double ) usid.getOpen_account_count()/usid.getRegister_count())*100 ) );
            }
            if(usid.getFirst_recharge_count() != 0){
                ktcgTosc[idx] = Double.valueOf( NumberUtil.formatNumber( ((double ) usid.getFirst_recharge_count()/usid.getOpen_account_count())*100 ) );
            }
            if(usid.getFirst_invest_count() != 0){
                scTost[idx] = Double.valueOf( NumberUtil.formatNumber( ((double ) usid.getFirst_invest_count()/usid.getFirst_recharge_count())*100 ) );
                all[idx] = Double.valueOf( NumberUtil.formatNumber( ((double ) usid.getFirst_invest_count()/usid.getRegister_count())*100 ) );
            }
        }

        request.setAttribute("dateList", JSON.toJSONString(dateList));
        request.setAttribute("zcToktcg", JSON.toJSONString(zcToktcg));
        request.setAttribute("ktcgTosc", JSON.toJSONString(ktcgTosc));
        request.setAttribute("scTost", JSON.toJSONString(scTost));
        request.setAttribute("all", JSON.toJSONString(all));

    }

	private List calcFunnelChartData(int transferPeriod, List<UserStatisticInfoModel> channelUserStatics) throws Exception {

        // 统计相关用户数
        UserStaticsInfoDto infoDto = calcUserCount(transferPeriod, channelUserStatics);

        // 计算转换率
        List funnelData = FrameUtil.newArrayList();
        double transferRate = infoDto.getRegister_count() == 0 ? 0 :100;
        double sortValue = transferRate;
        funnelData.add(FrameUtil.newHashMap("value", sortValue, "rate",NumberUtil.formatNumber(transferRate), "total", infoDto.getRegister_count(), "name", String.format("用户注册(%s)", infoDto.getRegister_count())));

        transferRate = infoDto.getRegister_count() == 0 ? 0 : ((double)infoDto.getOpen_account_count()/infoDto.getRegister_count())*100;
        sortValue = sortValue*(transferRate/100);
        funnelData.add(FrameUtil.newHashMap("value", sortValue, "rate", NumberUtil.formatNumber(transferRate), "total", infoDto.getOpen_account_count(), "name", String.format("开通存管(%s)", infoDto.getOpen_account_count())));

        transferRate = infoDto.getOpen_account_count() == 0 ? 0 : ((double)infoDto.getFirst_recharge_count()/infoDto.getOpen_account_count())*100;
        sortValue = sortValue*(transferRate/100);
        funnelData.add(FrameUtil.newHashMap("value", sortValue, "rate", NumberUtil.formatNumber(transferRate), "total", infoDto.getFirst_recharge_count(), "name", String.format("首次充值(%s)", infoDto.getFirst_recharge_count())));

        transferRate = infoDto.getFirst_recharge_count() == 0 ? 0 : ((double)infoDto.getFirst_invest_count()/infoDto.getFirst_recharge_count())*100;
        sortValue = sortValue*(transferRate/100);
        funnelData.add(FrameUtil.newHashMap("value", sortValue, "rate", NumberUtil.formatNumber(transferRate), "total", infoDto.getFirst_invest_count(), "name", String.format("首次投资(%s)", infoDto.getFirst_invest_count())));

        return funnelData;
    }

    /**
     * 计算各种类型的用户数
     *
     * @param transferPeriod 转化周期（天数） 0表示不考虑周期
     * @param channelUserStatics
     */
    private UserStaticsInfoDto calcUserCount(int transferPeriod, List<UserStatisticInfoModel> channelUserStatics) throws Exception {
        int register_count = channelUserStatics.size(); // 注册用户数
        int open_account_count = 0; // 开通存管用户数
        int first_recharge_count = 0; // 首次充值用户数
        int first_invest_count = 0; // 首次投资用户数

        UserStaticsInfoDto dto = new UserStaticsInfoDto();

        for(UserStatisticInfoModel usim : channelUserStatics){
            if(usim.getOpen_account_time() != null && usim.getOpen_account_time().longValue() > 0){
                if(DateUtil.getTimeStempBetweenDay(DateUtil.getFristSecond(usim.getRegister_time()), DateUtil.getLastSecond(usim.getOpen_account_time())) > transferPeriod ){
                    continue;
                }
                open_account_count += 1;
            }

            if(usim.getFirst_recharge_time() != null && usim.getFirst_recharge_time().longValue() > 0){
                if(DateUtil.getTimeStempBetweenDay(DateUtil.getFristSecond(usim.getRegister_time()), DateUtil.getLastSecond(usim.getFirst_recharge_time())) > transferPeriod ){
                    continue;
                }
                first_recharge_count += 1;
            }

            if(usim.getFirst_invest_time() != null && usim.getFirst_invest_time().longValue() > 0){
                if(DateUtil.getTimeStempBetweenDay(DateUtil.getFristSecond(usim.getRegister_time()), DateUtil.getLastSecond(usim.getFirst_invest_time())) > transferPeriod ){
                    continue;
                }
                first_invest_count += 1;
            }
        }

        dto.setRegister_count(register_count);
        dto.setOpen_account_count(open_account_count);
        dto.setFirst_recharge_count(first_recharge_count);
        dto.setFirst_invest_count(first_invest_count);
        return dto;
    }

    /**
     * 验证/补充 数据
     *
     * @param transferPeriod 转化周期（天数） 0表示不考虑周期
     * @param channelUserStatics
     */
    private void validateAndFilterData(int transferPeriod, List<UserStatisticInfoModel> channelUserStatics) throws Exception {
        if(channelUserStatics == null || channelUserStatics.size() == 0){
            return;
        }

        // 补充数据，如已首投的用户，首充时间为空（数据问题），则将首充时间默认为首投时间，依此类推
        UserStatisticInfoModel usim = null;
        Iterator<UserStatisticInfoModel> itr = channelUserStatics.iterator();
        while ( itr.hasNext() ) {
            usim = itr.next();
            if(usim.getUser_id() == null || usim.getUser_id().longValue() == 0){
                itr.remove();
                continue;
            }
            if( (usim.getFirst_recharge_time() == null || usim.getFirst_recharge_time() <= 0 ) && usim.getFirst_invest_time() != null){
                usim.setFirst_recharge_time(usim.getFirst_invest_time());
            }
            if( (usim.getOpen_account_time() == null || usim.getOpen_account_time() <= 0 ) && usim.getFirst_recharge_time() != null){
                usim.setOpen_account_time(usim.getFirst_recharge_time());
            }
            if( (usim.getRegister_time() == null || usim.getRegister_time() <= 0 ) && usim.getOpen_account_time() != null){
                usim.setRegister_time(usim.getOpen_account_time());
            }
        }
    }

    @ServiceRemoteProxy(serviceUrlResouceKey = RpmServiceKeyEnum.RPM_BI_SERVICE_KEY)
    private IInvalidChannelDataCommentService invalidChannelDataCommentService;

    @ServiceRemoteProxy(serviceUrlResouceKey = RpmServiceKeyEnum.RPM_BI_SERVICE_KEY)
	private IUserService userService;

	@ServiceRemoteProxy(serviceUrlResouceKey = RpmServiceKeyEnum.RPM_BI_SERVICE_KEY)
	private IMarketStatisticsService marketStatisticsService; 
	
	@ServiceRemoteProxy(serviceUrlResouceKey = RpmServiceKeyEnum.RPM_BI_SERVICE_KEY)
	private IMarketChannelService marketChannelService;
}
